<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<script src="../../resources/js-test.js"></script>
</head>
<body>
<script>
description("Test adding and removing tracks.");

var stream1;
var stream2;
var stream3;
var audioTrack;
var videoTrack;

function error() {
    testFailed('Stream generation failed.');
    finishJSTest();
}

function getUserMedia(dictionary, callback) {
    try {
        navigator.webkitGetUserMedia(dictionary, callback, error);
    } catch (e) {
        testFailed('webkitGetUserMedia threw exception :' + e);
        finishJSTest();
    }
}

function tryAddTrack(stream, track) {
    try {
        stream.addTrack(track);
    } catch (exception) {
        testFailed("addTrack threw an exception.");
        finishJSTest();
    }
}

function tryRemoveTrack(stream, track) {
    try {
        stream.removeTrack(track);
    } catch (exception) {
        testFailed("removeTrack threw an exception.");
        finishJSTest();
    }
}

function shouldNotFire() {
    testFailed("\"addtrack\" or \"removetrack\" events should not fire as a result of local addTrack() or removeTrack() operations.");
}

function onStreamInactive() {
    testPassed('Stream1 inactive.');
    shouldBeFalse('stream1.active');
    setTimeout(finishJSTest, 0);
}

function onStreamActive() {
    testPassed('Stream1 active.');
    shouldBeTrue('stream1.active');
    stream1.oninactive = onStreamInactive;
    tryRemoveTrack(stream1, stream3.getAudioTracks()[0]);
}

function gotStream3(s) {
    stream3 = s;
    stream1.onactive = onStreamActive;
    // onstreamactive doesn't work any more, so this test makes no more sense.
    // crbug.com/781716
    // tryAddTrack(stream1, stream3.getAudioTracks()[0]);
    finishJSTest();
}

function gotStream2(s) {
    stream2 = s;

    shouldBe('stream1.getAudioTracks().length', '1');
    shouldBe('stream1.getVideoTracks().length', '1');
    shouldBe('stream1.getTracks().length', '2');

    shouldBe('stream2.getAudioTracks().length', '1');
    shouldBe('stream2.getVideoTracks().length', '1');
    shouldBe('stream2.getTracks().length', '2');

    stream1.onaddtrack = shouldNotFire;
    stream1.onremovetrack = shouldNotFire;

    // remove a track of each kind
    audioTrack = stream1.getAudioTracks()[0];
    videoTrack = stream1.getVideoTracks()[0];

    tryRemoveTrack(stream1, audioTrack);
    // verify removed tracks
    shouldBe('stream1.getAudioTracks().length', '0');
    // verify that gettracks length is reduced by 1
    shouldBe('stream1.getTracks().length', '1');
    shouldBeNull('stream1.getTrackById(audioTrack.id)');
    // remove a non-existent (already removed) track (should not throw)
    tryRemoveTrack(stream1, audioTrack);
    // (re-)add tracks
    tryAddTrack(stream1, audioTrack);
    shouldBeNonNull('stream1.getTrackById(audioTrack.id)');
    shouldBe('audioTrack', 'stream1.getAudioTracks()[0]');

    tryRemoveTrack(stream1, videoTrack);
    shouldBe('stream1.getVideoTracks().length', '0');
    // verify that gettracks length is reduced by 1
    shouldBe('stream1.getTracks().length', '1');
    shouldBeNull('stream1.getTrackById(videoTrack.id)');
    tryRemoveTrack(stream1, videoTrack);
    tryAddTrack(stream1, videoTrack);

    // verify added tracks
    shouldBe('stream1.getAudioTracks().length', '1');
    shouldBe('stream1.getVideoTracks().length', '1');
    shouldBe('stream1.getTracks().length', '2');

    // verify that kind and label is preserved
    shouldBe('stream1.getAudioTracks()[0].kind', 'audioTrack.kind');
    shouldBe('stream1.getAudioTracks()[0].label', 'audioTrack.label');
    shouldBe('stream1.getVideoTracks()[0].kind', 'videoTrack.kind');
    shouldBe('stream1.getVideoTracks()[0].label', 'videoTrack.label');

    // try adding stream1's own tracks
    tryAddTrack(stream1, stream1.getAudioTracks()[0]);
    tryAddTrack(stream1, stream1.getVideoTracks()[0]);

    // verify that nothing has changed
    shouldBe('stream1.getAudioTracks().length', '1');
    shouldBe('stream1.getVideoTracks().length', '1');
    shouldBe('stream1.getTracks().length', '2');

    // add new tracks (from stream2)
    tryAddTrack(stream1, stream2.getAudioTracks()[0]);
    tryAddTrack(stream1, stream2.getVideoTracks()[0]);

    // verify added tracks
    shouldBe('stream1.getAudioTracks().length', '2');
    shouldBe('stream1.getVideoTracks().length', '2');
    shouldBe('stream1.getTracks().length', '4');

    // when all tracks have been removed, stream.active should return false.
    tryRemoveTrack(stream2, stream2.getAudioTracks()[0]);
    tryRemoveTrack(stream2, stream2.getVideoTracks()[0]);
    shouldBeFalse('stream2.active');

    // when all tracks have been stopped, stream.active should return false.
    for (var i = 0; i < stream1.getAudioTracks().length; i++)
        stream1.getAudioTracks()[i].stop();
    for (var i = 0; i < stream1.getVideoTracks().length; i++)
        stream1.getVideoTracks()[i].stop();
    shouldBeFalse('stream1.active');
    getUserMedia({audio:true, video:true}, gotStream3);
}

function gotStream1(s) {
    stream1 = s;
    getUserMedia({audio:true, video:true}, gotStream2);
}

getUserMedia({audio:true, video:true}, gotStream1);

window.jsTestIsAsync = true;
window.successfullyParsed = true;
</script>
</body>
</html>
